package com.rajaev.dtu.tractor.app.processor;

import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson.JSONObject;
import com.rajaev.dtu.tractor.app.service.SNotiMessageProcessor;
import com.rajaev.dtu.tractor.domain.entity.BatteryPo;
import com.rajaev.dtu.tractor.domain.entity.SnotiMessage;
import com.rajaev.dtu.tractor.domain.repository.mongo.SnotiMessageRepository;
import com.rajaev.dtu.tractor.infrastructure.base.enums.SnotiEventType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Optional;

/**
 * 这里使用模板方法模式，对消息的处理进行定义。
 */
@Slf4j
public abstract class AbstractSNotiMessageProcessor implements SNotiMessageProcessor {

    @Autowired
    SnotiMessageRepository snotiMessageRepository;

    @Override
    public void processMessage(SnotiMessage snotiMessage) {

        //判断设备是否已经注册
        BatteryPo thisBattery = isLogOn(snotiMessage);
        if (thisBattery == null) {
            Optional<String> vinOptional = getVinFromSnotiMessage(snotiMessage);
            if (vinOptional.isPresent()) {
                thisBattery = doLogonOn(vinOptional.get(), snotiMessage.getDid());
                if (thisBattery == null) {
                    return;
                }
            } else {
                return;
            }

        }
        try {

            SnotiMessageContextHolder.initContext(thisBattery, snotiMessage);

            SnotiEventType snotiEventType = SnotiEventType.getType(snotiMessage.getEvent_type());

            switch (snotiEventType) {
                case ONLINE:
                    processDeviceLogin();
                    break;
                case KV: {

                    saveMessageInMongo();

                    //设置设备的温度个数和单体个数
                    processDeviceTempAndCellNum();

                    //处理设备的充电 和放电报文
                    processDeviceChargeOrDischarge();

                    //解析动态信息
                    parseDeviceMonitor();

                    //记录设备的故障
                    processDeviceFault();
                }
                break;
                case OFFLINE: {
                    processDeviceLogout();
                }
                break;
                case GPS_KV: {
                    processDeviceGps();
                }
                default: {

                    log.warn("没有指定解析的报文类型：[{}]", snotiMessage.getData().toJSONString());
                }

            }


        } finally {
            SnotiMessageContextHolder.clear();
        }
    }

    public Optional<String> getVinFromSnotiMessage(SnotiMessage snotiMessage) {
        JSONObject jsonObject = snotiMessage.getData();
        String hexVin = jsonObject.getString("VIN");
        if (StringUtils.isNotEmpty(hexVin)) {
            return Optional.of(StringUtils.trim(HexUtil.decodeHexStr(hexVin)));
        } else {
            return Optional.empty();
        }
    }

    public abstract void parseDeviceMonitor();


    /**
     * 记录设备的充电和放电报文
     */
    public abstract void processDeviceChargeOrDischarge();

    /**
     * 判断设备是否已经注册
     *
     * @param snotiMessage
     * @return
     */
    public abstract BatteryPo isLogOn(SnotiMessage snotiMessage);

    /**
     * 对设备did和vin进行绑定。
     *
     * @param vin vin
     * @param did did
     */
    public abstract BatteryPo doLogonOn(String vin, String did);

    public abstract void processDeviceFault();


    /**
     * 处理设备上线
     *
     * @return true/false 如果设备不存在或者未注册，则返回false。
     */
    public abstract void processDeviceLogin();

    public void saveMessageInMongo(){
        SnotiMessage snotiMessage = SnotiMessageContextHolder.getSnotiMessage();
        BatteryPo batteryPo = SnotiMessageContextHolder.getTargetBattery();
        JSONObject jsonObject = snotiMessageRepository.createCommonMongoMessageHeader(batteryPo,snotiMessage);
        snotiMessageRepository.saveInMongo(jsonObject);
    }


    /**
     * 处理设备的温度个数和单体个数
     */
    public abstract void processDeviceTempAndCellNum();

    public abstract void processDeviceGps();


    /**
     * 处理设备下线
     */
    public abstract void processDeviceLogout();

}
